﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using XCaptcha;

namespace Eacademy.Library.Validations
{

    public class DataAnnotationsMustMatchPropertyValidator : DataAnnotationsModelValidator<MustMatchPropertyAttribute>
    {
        public DataAnnotationsMustMatchPropertyValidator(ModelMetadata metadata, ControllerContext context, MustMatchPropertyAttribute attribute)
            : base(metadata, context, attribute)
        {

        }
        public override IEnumerable<ModelValidationResult> Validate(object container)
        {
            var propertyToMatch = Metadata.ContainerType.GetProperty(Attribute.PropertyToMatch);
            if (propertyToMatch != null)
            {
                var valueToMatch = propertyToMatch.GetValue(container, null);
                var value = Metadata.Model;

                bool valid = Equals(value, valueToMatch);
                if (!valid)
                {
                    yield return new ModelValidationResult { Message = ErrorMessage };
                }
            }

            // we're not calling base.Validate here so that the attribute IsValid method doesn't get called
        }
    }

    public class DataAnnotationsMustMatchObjectPropertyValidator : DataAnnotationsModelValidator<MustMatchObjectPropertyAttribute>
    {
        public DataAnnotationsMustMatchObjectPropertyValidator(ModelMetadata metadata, ControllerContext context, MustMatchObjectPropertyAttribute attribute)
            : base(metadata, context, attribute)
        {

        }


        public override IEnumerable<ModelValidationResult> Validate(object container)
        {
            string[] words = Attribute.PropertyToMatch.Split('.');
            var classPropertyToMatch = Metadata.ContainerType.GetProperty(words[0]);
            object propertyContainerToMatch = classPropertyToMatch.GetValue(container, null);
            var propertyToMatch = propertyContainerToMatch.GetType().GetProperty(words[1]);

            if (propertyToMatch != null)
            {
                var valueToMatch = propertyToMatch.GetValue(propertyContainerToMatch, null);
                var value = Metadata.Model;

                bool valid = Equals(value, valueToMatch);
                if (!valid)
                {
                    yield return new ModelValidationResult { Message = ErrorMessage };
                }
            }

            // we're not calling base.Validate here so that the attribute IsValid method doesn't get called
        }
    }

    public class DataAnnotationsMustMatchEncryptedSolutionValidator : DataAnnotationsModelValidator<MustMatchEncryptedSolutionAttribute>
    {
        public DataAnnotationsMustMatchEncryptedSolutionValidator(ModelMetadata metadata, ControllerContext context, MustMatchEncryptedSolutionAttribute attribute)
            : base(metadata, context, attribute)
        {

        }


        public override IEnumerable<ModelValidationResult> Validate(object container)
        {
            var encryptedSolution = Metadata.ContainerType.GetProperty(Attribute.EncryptedSolutionProperty);
            var encryptedValue = encryptedSolution.GetValue(container, null);
            var attempt = Metadata.Model;

            if (encryptedValue != null)
            {

                string solution = String.Empty;
                bool valid = false;

                if (attempt != null)
                {
                    solution = Attribute.EncryptionProvider.Decrypt(HttpUtility.UrlDecode(encryptedValue.ToString()), Attribute.SecretKey);
                    valid = String.Equals(attempt.ToString(), solution, StringComparison.CurrentCultureIgnoreCase);
                }


                if (!valid)
                {
                    yield return new ModelValidationResult { Message = ErrorMessage };
                }
            }

            // we're not calling base.Validate here so that the attribute IsValid method doesn't get called
        }
    }
}